package com.hyper_yang._04_jvm.chap06;

import java.lang.ref.PhantomReference;
import java.lang.ref.ReferenceQueue;
import java.lang.ref.SoftReference;
import java.lang.ref.WeakReference;
import java.util.concurrent.TimeUnit;

public class FourReferenceDemo {
    public static void main(String[] args) {
        PhantomReference();
    }

    private static void PhantomReference() {
        User user = new User(1, "zhangsan");
        ReferenceQueue<Object> referenceQueue = new ReferenceQueue<>();
        PhantomReference<Object> phantomRef = new PhantomReference<>(user, referenceQueue);

        user = null; // 解除强引用
        // 在这里，对象可能已经被垃圾回收了，但我们无法通过虚引用获取它

        // 判断虚引用是否被回收
        boolean isCollected = false;

        while (!isCollected) {
            System.gc(); // 建议垃圾回收器执行回收操作,只是申请，不是立刻+马上+now执行
            try {
                Thread.sleep(1000); // 等待1秒钟
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            if (phantomRef.isEnqueued()) { //判断虚引用是否已经被回收。
                isCollected = true;
            }
        }
        // 输出虚引用是否被回收
        System.out.println("虚引用是否被回收：" + isCollected);
    }

    /**
     * 弱引用
     * 无论内存是否足够都会回收掉只被弱引用关联的对象
     */
    private static void WeakReference() {
        //构造了弱引用
        WeakReference<User> userWeakRef = new WeakReference<>(new User(1, "zhangsan"));
        //从弱引用中重新获取对象
        System.out.println(userWeakRef.get());

        System.gc();

        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }

        // 不管当前内存空间足够与否，都会回收它的内存
        System.out.println("WeakReference After GC:");
        //重新尝试从弱引用中获取对象
        System.out.println(userWeakRef.get());
    }

    /**
     * 软引用
     * 分两次运行演示
     * 第1次，没有任何配置用默认，内存够用可以获得
     * 第2次, 配置-Xms10m -Xmx10m，内存不足测试：让系统认为内存资源紧张
     */
    private static void SoftReference() {
        //创建对象，建立软引用
        SoftReference<User> userSoftRef = new SoftReference<>(new User(1, "zhangsan"));
        //从软引用中获得强引用对象
        System.out.println(userSoftRef.get());

        try {
            //默认新生代占堆的1/3空间，老年代占堆的2/3空间，因此7m的内容在哪个空间都放不下
            byte[] b = new byte[1024 * 1024 * 7]; //7M
        } catch (Throwable e) {
            e.printStackTrace();
        } finally {
            System.out.println("finally");
            //再次从软引用中获取数据，在报OOM之前，垃圾回收器会回收软引用的可达对象。
            System.out.println(userSoftRef.get());
        }
    }

    /**
     * 强引用
     */
    private static void StrongReference() {
        //定义强引用
        User user = new User(1, "zhangsan");
        //定义强引用
        User user2 = user;

        //设置user为null，User对象不会被回收，因为依然被user2引用
        user = null;

        //强制垃圾回收
        System.gc();

        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        System.out.println(user2);
    }
}


